/**

九、Object对象方法
   在JavaScript中，几乎所有的对象都是Object类型的实例，它们都会从Object.prototype继承属性和方法，
   虽然大部分属性都会被覆盖（shadowed）或者说被重写了（overridden）。 
   除此之外，Object 还可以被故意的创建，但是这个对象并不是一个“真正的对象”（例如：通过 Object.create(null)），
   或者通过一些手段改变对象，使其不再是一个“真正的对象”（比如说: Object.setPrototypeOf）。
   
   通过原型链，所有的 object 都能观察到 Object 原型对象（Object prototype object）的改变，
   除非这些受到改变影响的属性和方法沿着原型链被进一步的重写。尽管有潜在的危险，
   但这为覆盖或扩展对象的行为提供了一个非常强大的机制。

   Object 构造函数为给定的参数创建一个包装类对象（object wrapper），具体有以下情况：

   - 1、如果给定值是 null 或 undefined，将会创建并返回一个空对象
   - 2、如果传进去的是一个基本类型的值，则会构造其包装类型的对象
   - 3、如果传进去的是引用类型的值，仍然会返回这个值，经他们复制的变量保有和源对象相同的引用地址

   当以非构造函数形式被调用时，Object 的行为等同于 new Object()。

   可查看 对象初始化/字面量语法。
  ```js
    var o = {};
    var o = {a: 'foo', b: 42, c: {}};

    var a = 'foo', b = 42, c = {};
    var o = {a: a, b: b, c: c};

    var o = {
    property: function ([parameters]) {},
    get property() {},
    set property(value) {}
    };
  ```

(二)、从一个对象上删除一个属性

   Object 自身没有提供方法删除其自身属性（Map 中的 Map.prototype.delete() 可以删除自身属性 ）为了删除对象上的属性，必须使用 delete 操作符

(三)、构造函数
     Object()
       创建一个新的 Object 对象。该对象将会包裹（wrapper）传入的参数
(四)、静态方法
     ```html
        Object.assign():           通过复制一个或多个对象来创建一个新的对象。
        Object.create({}):           使用指定的原型对象和属性创建一个新对象。
        Object.defineProperty(obj,prop):   给对象添加一个属性并指定该属性的配置。
        obj : 在其上定义或修改属性的对象。
        props:要定义其可枚举属性或修改的属性描述符的对象。
              对象中存在的属性描述符主要有两种：数据描述符和访问器描述符（更多详情，请参阅Object.defineProperty()）。
               描述符具有以下键：
            configurable : true 只有该属性描述符的类型可以被改变并且该属性可以从对应对象中删除。 默认为 false
            enumerable: true 只有在枚举相应对象上的属性时该属性显现。默认为 false
            value:与属性关联的值。可以是任何有效的JavaScript值（数字，对象，函数等）。默认为 undefined.
            writable:true只有与该属性相关联的值被assignment operator (en-US)改变时。 默认为 false
            get: 作为该属性的 getter 函数，如果没有 getter 则为undefined。
                 函数返回值将被用作属性的值。默认为 undefined
            set:作为属性的 setter 函数，如果没有 setter 则为undefined。
                 函数将仅接受参数赋值给该属性的新值。默认为 undefined
        Object.defineProperties(): 给对象添加多个属性并分别指定它们的配置。
        Object.entries():          返回给定对象自身可枚举属性的 [key, value] 数组。
        Object.freeze()            冻结对象：其他代码不能删除或更改任何属性。
        Object.getOwnPropertyDescriptor(): 返回对象指定的属性配置。
        Object.getOwnPropertyNames():      返回一个数组，它包含了指定对象所有的可枚举或不可枚举的属性名。
        Object.getOwnPropertySymbols()     返回一个数组，它包含了指定对象自身所有的符号属性。
        Object.getPrototypeOf()            返回指定对象的原型对象。
        Object.is()                        比较两个值是否相同。所有 NaN 值都相等（这与==和===不同）。
        Object.isExtensible()              判断对象是否可扩展。
        Object.isFrozen()                  判断对象是否已经冻结。
        Object.isSealed()                  判断对象是否已经密封。
        Object.keys()                      返回一个包含所有给定对象自身可枚举属性名称的数组。
        Object.preventExtensions()         防止对象的任何扩展。
        Object.seal()                      防止其他代码删除对象的属性。
        Object.setPrototypeOf()            设置对象的原型（即内部 [[Prototype]] 属性）。
        Object.values()                    返回给定对象自身可枚举值的数组。
        
        实例属性

        Object.prototype.constructor      一个引用值，指向 Object 构造函数
        Object.prototype.__proto__        指向一个对象，当一个 object 实例化时，使用该对象作为实例化对象的原型
        
        实例方法

        Object.prototype.__defineGetter__()
        将一个属性与一个函数相关联，当该属性被访问时，执行该函数，并且返回函数的返回值。
        Object.prototype.__defineSetter__()
        将一个属性与一个函数相关联，当该属性被设置时，执行该函数，执行该函数去修改某个属性。
        Object.prototype.__lookupGetter__()
        返回一个函数，该函数通过给定属性的 Object.prototype.__defineGetter__() 得出。
        Object.prototype.__lookupSetter__()
        返回一个函数，该函数通过给定属性的 Object.prototype.__defineSetter__() 得出。

        Object.prototype.hasOwnProperty(): 返回一个布尔值，用于表示一个对象自身是否包含指定的属性，该方法并不会查找原型链上继承来的属性。
        Object.prototype.isPrototypeOf(): 返回一个布尔值，用于表示该方法所调用的对象是否在指定对象的原型链中。
        Object.prototype.propertyIsEnumerable(): 返回一个布尔值，用于表示内部属性 ECMAScript [[Enumerable]] attribute 是否被设置。
        Object.prototype.toLocaleString() :调用 toString()。
        Object.prototype.toString():返回一个代表该对象的字符串。
        Object.prototype.valueOf():返回指定对象的原始值。
     ```
 */
const obj = {
    name: "小费",
    age: 23,
    gender: "男",
    add: function (obj) {
        console.log("添加对象：", obj)
    },
    run() {
        console.log("开始跑········")
    }
}
Object.keys(obj).forEach(key => { 
    console.log(key) //name  age gender add  run
})

Object.values(obj).forEach(value => {
    console.log(value)
})
//小费 
//23 
//男  
//ƒ(obj) { console.log("添加对象：", obj) } 
//ƒ run() { console.log("开始跑········") }
Object.entries(obj).forEach(item => { 
    console.log(item)
})
/**
 * (2) ['name', '小费']
 (2) ['age', 23]
 (2) ['gender', '男']
 (2) ['add', ƒ]
 (2) ['run', ƒ]
 */
const map = new Map(Object.entries(obj))
console.log(map) // Map(5) {'name' => '小费', 'age' => 23, 'gender' => '男', 'add' => ƒ, 'run' => ƒ}
console.log(map['name']) //undefined
const prop = 'address'
let value = ""
const proxy = Object.defineProperty(obj, prop, {
    configurable: true,
    enumerable: true,
    // value:true,
    // writable:true,
    get: function () {
        return value
    },
    set: function (newValue) {
        debugger
        if (Array.isArray(obj[prop])) {
            obj[prop].push(newValue)
        } else {
            obj[prop] = [newValue] 
        }
    },
})
console.log("proxy:", proxy) //name: '小费', age: 23, gender: '男', add: ƒ, run: ƒ, …}
// proxy.address.push("1311")

const properties = Object.getOwnPropertyDescriptors(obj)
console.log(properties) 

console.log(obj.toLocaleString())
console.log(obj.toString())
/**
 {
    add: { writable: true, enumerable: true, configurable: true, value: ƒ }
    address: { enumerable: true, configurable: true, get: ƒ, set: ƒ }
    age: { value: 23, writable: true, enumerable: true, configurable: true }
    gender: { value: '男', writable: true, enumerable: true, configurable: true }
    name: { value: '小费', writable: true, enumerable: true, configurable: true }
    run: { writable: true, enumerable: true, configurable: true, value: ƒ }
    [[Prototype]]: Object
 }
 */

const obj1 = Object.create(null, {
    name: {
        value: "小费",
        writable: true,
        configurable: true,
        enumerable:true
    }
})

console.log(obj1)

var obj2 = {};
Object.defineProperties(obj2, {
    'property1': {
        value: true,
        writable: true
    },
    'property2': {
        value: 'Hello',
        writable: false
    }
});

